﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Common.Utils;
using Common.Exp2D;

namespace Common.Particles
{
    public class Particle2D : Object2D
    {
        public static int m_defaultParticleMass = 3;
        
        public static float m_minScale = 1f;
        public static float m_maxScale = 0.2f;

        private float m_rotationSpeed;        

        private static Random m_random = new Random();

        protected List<Object2D> m_trailList;

        protected bool m_hasTrail = false;
        public bool HasTrail
        {
            get { return m_hasTrail; }
            set { m_hasTrail = value; }
        }        

        //Life in milliseconds
        protected bool m_visible = true;
        public bool Visible
        {
            get { return m_visible; }
            set { m_visible = value; }
        }
        protected int m_life = 0;
        public int Life
        {
            get { return m_life; }
            set 
            {
                m_life = value;
                m_particleLifeTime = m_life;
            }
        }

        protected int m_particleLifeTime;
        public int LifeTime
        {
            get { return m_particleLifeTime; }
        }

        public Vector2 m_velocity;
        public Vector2 Velocity
        {
            get { return m_velocity; }
            set { m_velocity = value; }
        }

        protected Vector2 m_acceleration = Vector2.Zero;

        protected int m_maxTrailLength;

        protected Queue<Object2D> m_trailQueue;

        protected bool m_fadeEffect;

        public Particle2D(Texture2D texture, Vector2 position, int life, bool fadeEffect)
            : base (texture, position, true)
        {
            m_collidable = false;
            m_life = life;
            m_particleLifeTime = life;
            m_scale = m_minScale;
            m_rotation = 0 + (float)m_random.NextDouble() * (0 - MathHelper.TwoPi);
            m_rotationSpeed = 0 + (float)m_random.NextDouble() * (0 - 3);
            m_fadeEffect = fadeEffect;
        }

        public Particle2D(Texture2D texture, Vector2 position, bool hasTrail, int trailLength, int life)
            : this (texture, position, life, true)
        {
            m_hasTrail = hasTrail;
            m_trailList = new List<Object2D>();
            m_maxTrailLength = trailLength;
            m_trailQueue = new Queue<Object2D>();
            for (int i = 0; i < trailLength; i++)
            {
                Object2D trailNode = new Object2D(m_texture, Vector2.Zero, true);
                m_trailQueue.Enqueue (trailNode);
            }
        }

        public override void Draw(GameTime time, SpriteBatch spriteBatch)
        {
            if (m_life > 0 && m_visible)
            {   
                if (m_hasTrail)
                {
                    DrawTrail(time, spriteBatch);
                }
                base.Draw(time, spriteBatch);
            }
        }

        private void DrawTrail(GameTime time, SpriteBatch spriteBatch)
        {
            for (int i = 0; i < m_trailList.Count; i++)
                m_trailList[i].Draw(time, spriteBatch);
        }

        private void UpdateTrail(Vector2 position, GameTime time)
        {   
            if (m_trailList.Count >= m_maxTrailLength)
            {
                Object2D trailNode = m_trailList[m_trailList.Count - 1];
                trailNode.Position = Vector2.Zero;
                m_trailQueue.Enqueue(trailNode);
                m_trailList.RemoveAt(m_trailList.Count - 1);
            }
            else
            {
                if (m_trailQueue.Count > 0)
                {
                    Object2D trailNode = m_trailQueue.Dequeue();
                    trailNode.Position = position;
                    m_trailList.Insert(0, trailNode);
                }
            }
             
            for (int i = 0 ; i < m_trailList.Count ; i++)
            {
                m_trailList [i].Color = m_color;                
            }  
        }

        public new void Update(GameTime time)
        {            
            float deltaS = (float)time.ElapsedGameTime.TotalSeconds;
            m_life -= time.ElapsedGameTime.Milliseconds;
            m_velocity += (m_mass * Environement2D.Instance.Gravity + Environement2D.Instance.Wind + Environement2D.Instance.AirFriction) * deltaS;
            Vector2 oldPosition = m_position;
            m_position += m_velocity;
            m_rotation += m_rotationSpeed * deltaS;


            if (m_life >= 0)
            {
                if (m_fadeEffect)
                    m_color.A = (byte)MathHelper.Lerp(Byte.MaxValue, Byte.MinValue, 1 - m_life / (float)m_particleLifeTime);
                m_scale = MathHelper.Lerp(m_minScale, m_maxScale, 1 - m_life / (float)m_particleLifeTime);

                if (m_hasTrail)
                    UpdateTrail(oldPosition, time);
            }
            else
            {
                if (m_hasTrail)
                {
                    //Reinit trail queue
                    for (int i = 0; i < m_trailList.Count; i++)
                        m_trailQueue.Enqueue(m_trailList[i]);
                    m_trailList.Clear();
                }
            }

        }
    }
}
